package sk.ownage.p1.featurestore;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import android.os.Environment;
import android.util.Log;

public class TrackWriter {
	private final String TAG="TrackWriter";
	private final String rootPath=Environment.getExternalStorageDirectory()+"/featureStore"+"/tracks";
	private final int DIRECTORY_MAX=TrackStore.DIRECTORY_MAX;;
	private String trackPath="";
	private int Id=0;
	public final int START_FILE=0;
	public final int NAME_WRITTEN=1;
	public final int ACTIVITY_WRITTEN=2;
	public final int TIMESTAMP_WRITTEN=3;
	public final int DESCRIPTION_WRITTEN=4;
	public final int DESCRIPTION_EMPTY_WRITTEN=41;
	public final int NEW_TRACK_FLAG__WRITTEN=5;
	public final int NEW_SEGMENT_FLAG__WRITTEN=6;
	public final int NEW_WAYPOINT_FLAG__WRITTEN=7;
	public final int WAYPOINT_LATITUDE_WRITTEN=71;
	public final int WAYPOINT_LONGITUDE_WRITTEN=72;
	public final int WAYPOINT_ALTITUDE_WRITTEN=73;
	public final int WAYPOINT_TIMESTAMP_WRITTEN=74;
	public final int END_SEGMENT_FLAG__WRITTEN=61;
	public final int END_TRACK_FLAG__WRITTEN=51;
	public final int END_FILE_FLAG__WRITTEN=8;
	public final int FILE_CLOSED_SUCCESSFUL=9;
	private int writerState=0;
	private ObjectOutputStream os;
	
	
	
	public TrackWriter(){
		this("");
	}
	
	public TrackWriter(String trackRootPath){
		Id=loadMaxId()+1;
		int folderId=Id/DIRECTORY_MAX;
		int fileId=Id%DIRECTORY_MAX;
		String folderPath=(((folderId/100)>0)?"":"0")+(((folderId/10)>0)?"":"0")+folderId;
		String filePath=(((fileId/100)>0)?"":"0")+(((fileId/10)>0)?"":"0")+fileId;
		trackPath=((!trackRootPath.equals(""))?trackRootPath:rootPath)+"/"+folderPath+"/"+filePath+".bin";
		File folder=new File(rootPath+"/"+folderPath);
		File trackFile=new File(trackPath);
		if(!folder.exists())
			folder.mkdirs();
			try {
				FileOutputStream fos = new FileOutputStream(trackFile);
				os = new ObjectOutputStream(new BufferedOutputStream(fos));
				writerState=START_FILE;
			} catch (Exception e) {
				Log.d(TAG, e.toString());
				e.printStackTrace();
			}
	}
	
	public void writeName(String name) throws Exception{
		if(writerState==START_FILE){
			try {
				os.writeByte(1);
				os.writeUTF(name);
				writerState=NAME_WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		} 
		else{
			throw new Exception("Cannot write Name at this state!");
		}
	}
	
	public void writeActivity(String activity) throws Exception{
		if(writerState==NAME_WRITTEN){
			try {
				os.writeByte(1);
				os.writeUTF(activity);
				writerState=ACTIVITY_WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		} 
		else{
			throw new Exception("Cannot write Activity name at this state!");
		}
	}
	
	public void writeTimestamp(long timestamp) throws Exception{
		if(writerState==ACTIVITY_WRITTEN){
			try {
				os.writeByte(1);
				os.writeLong(timestamp);
				writerState=TIMESTAMP_WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		} 
		else{
			throw new Exception("Cannot write Timestamp at this state!");
		}
	}
	
	public void writeDescription(String desc) throws Exception{
		if(writerState==TIMESTAMP_WRITTEN){
			try {
				if(desc==""){
					os.writeByte(0);
					writerState=DESCRIPTION_EMPTY_WRITTEN;
				}else{
					os.writeByte(1);
					os.writeUTF(desc);
					writerState=DESCRIPTION_WRITTEN;
				}
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write Description at this state!");
		}
	}
	
	public void writeTrackStartFlag() throws Exception{
		if(writerState==DESCRIPTION_WRITTEN || writerState==DESCRIPTION_EMPTY_WRITTEN|| writerState==END_TRACK_FLAG__WRITTEN){
			try {
				os.writeByte(1);
				writerState=NEW_TRACK_FLAG__WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write NewTrack flag at this state!");
		}
	}
	
	public void writeSegmentStartFlag() throws Exception{
		if(writerState==NEW_TRACK_FLAG__WRITTEN || writerState==END_SEGMENT_FLAG__WRITTEN){
			try {
				os.writeByte(1);
				writerState=NEW_SEGMENT_FLAG__WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write NewSegment flag at this state!");
		}
	}
	
	public boolean writeWaypointStartFlag() throws Exception{
		boolean result=false;
		if(writerState==NEW_SEGMENT_FLAG__WRITTEN || writerState==WAYPOINT_TIMESTAMP_WRITTEN){
			try {
				os.writeByte(1);
				writerState=NEW_WAYPOINT_FLAG__WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
			return result;
		}
		else{
			throw new Exception("Cannot write NewPoint flag at this state!");
		}
	}
	
	public void writeWaypointLatitude(double latitude) throws Exception{
		if(writerState==NEW_WAYPOINT_FLAG__WRITTEN){
			try {
				os.writeDouble(latitude);
				writerState=WAYPOINT_LATITUDE_WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write waypoint latitude at this state!");
		}
	}
	
	public void writeWaypointLongitude(double longitude) throws Exception{
		if(writerState==WAYPOINT_LATITUDE_WRITTEN){
			try {
				os.writeDouble(longitude);
				writerState=WAYPOINT_LONGITUDE_WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write waypoint longitude at this state!");
		}
	}
	
	public void writeWaypointAltitude(double altitude) throws Exception{
		if(writerState==WAYPOINT_LONGITUDE_WRITTEN){
			try {
				os.writeDouble(altitude);
				writerState=WAYPOINT_ALTITUDE_WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write waypoint altitude at this state!");
		}
	}
	
	public void writeWaypointTimestamp(long timestamp) throws Exception{
		if(writerState==WAYPOINT_ALTITUDE_WRITTEN){
			try {
				os.writeLong(timestamp);
				writerState=WAYPOINT_TIMESTAMP_WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write waypoint timestamp at this state!");
		}
	}
	

	public void writeSegmentEndFlag() throws Exception{
		if(writerState==WAYPOINT_TIMESTAMP_WRITTEN || writerState==NEW_SEGMENT_FLAG__WRITTEN){
			try {
				//if(writerState==62)os.writeByte(0);//kvoli ukonceniu trackpointov
				os.writeByte(0);
				writerState=END_SEGMENT_FLAG__WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write EndSegment flag at this state!");
		}
	}
	
	public void writeTrackEndFlag() throws Exception{
		if(writerState==NEW_TRACK_FLAG__WRITTEN || writerState==END_SEGMENT_FLAG__WRITTEN){
			try {
				os.writeByte(0);
				writerState=END_TRACK_FLAG__WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write EndTrack flag at this state!");
		}
	}
		
	
	public void writeFileEndFlag() throws Exception{
		if(writerState==END_TRACK_FLAG__WRITTEN || writerState==DESCRIPTION_WRITTEN || writerState==DESCRIPTION_EMPTY_WRITTEN){
			try {
				os.writeByte(0);
				writerState=END_FILE_FLAG__WRITTEN;
			} catch (Exception e) {
				Log.d(TAG,e.toString());
				e.printStackTrace();
			}
		}
		else{
			throw new Exception("Cannot write EndFile flag at this state!");
		}
	}
	
	public void endFile() throws Exception{
		if(writerState==END_FILE_FLAG__WRITTEN){
			try {
				os.close();
				saveMaxId();
			} catch (IOException e) {
				Log.d(TAG, e.toString());
				e.printStackTrace();
			}
		}else{
			throw new Exception("Cannot close file at this state!");
		}
		
	}
	
	public void closeWriter(){
		try {
			os.close();
		} catch (IOException e) {
			Log.d(TAG, e.toString());
			e.printStackTrace();
		}
	}
	
	
	private int loadMaxId(){
		File maxIdpath=new File(rootPath+"/"+"maxId.bin");
		int result=-1;
		if(maxIdpath.exists())
		try {
			FileInputStream fis = new FileInputStream(maxIdpath);
			ObjectInputStream is = new ObjectInputStream(fis);
			result=is.readInt();
			is.close();
		} catch (Exception e) {
			Log.d(TAG, e.toString());
		}
		return result;
	}
	
	private void saveMaxId(){
		File maxIdpath=new File(rootPath+"/"+"maxId.bin");
		//if(maxIdpath.exists())
		try {
			FileOutputStream fos = new FileOutputStream(maxIdpath);
			ObjectOutputStream os = new ObjectOutputStream(fos);
			os.writeInt(Id);
			os.close();
		} catch (Exception e) {
			Log.d(TAG, e.toString());
		}
	}
	
	public int getActualTrackId(){
		return this.Id;
	}

}
